/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.alphawavesgames.engine.rendering;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;

/**
 *
 * @author duncan
 */
public class GLSpriteRenderer extends SpriteRenderer
{
    //the gl render interface
    private GLRenderHWInterface m_renderInterface;
    private GLTextureManager    m_textureManager;
    /** The buffer holding the vertices */
    private FloatBuffer m_vertexBuffer;
    /** The buffer holding the texture coordinates */
    private FloatBuffer m_textureBuffer;
    /** The buffer holding the indices */
    private ShortBuffer m_indexBuffer;

    private static float sm_InitVertices[] =
    {
            1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f,
            1.0f, 1.0f, 0.0f,
    };

    private static final float sm_initTexCoords[] =
    {
            1.0f, 1.0f,
            0.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };

    private static final short sm_initIndices[] =
    {
            0,1,2,
            0,2,3,
    };

    public GLSpriteRenderer()
    {
        m_renderInterface = null;
        m_textureManager = null;
    }

    @Override
    public void initialise( RenderContainer renderContainer )
    {
        GLRenderContainer glRC = (GLRenderContainer)renderContainer;
        m_renderInterface = glRC.getRenderHWInterface();
        m_textureManager = glRC.getTextureManagerGL();
    }

    public void initialise( GLRenderContainer renderContainer )
    {
        m_renderInterface = renderContainer.getRenderHWInterface();
        m_textureManager = renderContainer.getTextureManagerGL();
    }
    //using more immediate style rendering for now - sprite rendering handled by the sprite class itself

    @Override
    public Sprite createSprite( TextureManager.TextureHandle texture, int x, int y, int width, int height )
    {
        return new GLSprite( texture, x, y, width, height );
    }

    @Override
    public Sprite createSprite( TextureManager.TextureHandle texture )
    {
        return new GLSprite( texture );
    }

    public class GLSprite extends Sprite
    {

        protected GLSprite( TextureManager.TextureHandle texHandle )
        {
            super( texHandle );

            initBuffers();
        }

        protected GLSprite( TextureManager.TextureHandle texture, int x, int y, int width, int height )
        {
            super( texture, x, y, width, height );

            initBuffers();
        }

        @Override
        public void setPosAndExtents( int x, int y, int width, int height )
        {
            super.setPosAndExtents( x, y, width, height );
            float screenX = (float)x;//( ( x / m_renderInterface.getScreenWidth() ) * 2.0f ) - 1.0f;
            float screenY = (float)y;//( ( y / m_renderInterface.getScreenHeight() ) * 2.0f ) - 1.0f;
            float screenWidth = (float)width;//( ( width / m_renderInterface.getScreenWidth() ) * 2.0f );
            float screenHeight = (float)height;//( ( height / m_renderInterface.getScreenHeight() ) * 2.0f );

            //bottom right
            m_vertexBuffer.put( 0, screenX + screenWidth );
            m_vertexBuffer.put( 1, screenY  );

            //bottom left
            m_vertexBuffer.put( 3, screenX );
            m_vertexBuffer.put( 4, screenY  );

            //top left
            m_vertexBuffer.put( 6, screenX );
            m_vertexBuffer.put( 7, screenY + screenHeight);

            //top right
            m_vertexBuffer.put( 9, screenX + screenWidth );
            m_vertexBuffer.put( 10, screenY + screenHeight);
        }

        protected void initBuffers()
        {
            ByteBuffer byteBuf = ByteBuffer.allocateDirect(sm_InitVertices.length * 4);
            byteBuf.order(ByteOrder.nativeOrder());
            m_vertexBuffer = byteBuf.asFloatBuffer();
            m_vertexBuffer.put(sm_InitVertices);
            m_vertexBuffer.position(0);

            //
            byteBuf = ByteBuffer.allocateDirect(sm_initTexCoords.length * 4);
            byteBuf.order(ByteOrder.nativeOrder());
            m_textureBuffer = byteBuf.asFloatBuffer();
            m_textureBuffer.put(sm_initTexCoords);
            m_textureBuffer.position(0);

            //
            byteBuf = ByteBuffer.allocateDirect( sm_initIndices.length * 2 );
            byteBuf.order(ByteOrder.nativeOrder());
            m_indexBuffer = byteBuf.asShortBuffer();
            m_indexBuffer.put( sm_initIndices );
            m_indexBuffer.position(0);
        }


        @Override
        public void draw()
        {
            GLTextureManager.TextureGL texRes = m_textureManager.getTexture( m_texture );

            if( texRes != null )
            {
                //looks slow, need a better threading model
                GL10 gl = m_renderInterface.lockGL();

                try
                {
                    if( gl != null )
                    {
                        //get the gl texture handle and bind the texture

                        //draw the vertex buffer
                        //Bind our only previously generated texture in this case
                        gl.glBindTexture(GL10.GL_TEXTURE_2D, texRes.getGLTex() );

                        //Point to our buffers
                        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
                        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

                        //Set the face rotation
                        gl.glFrontFace(GL10.GL_CCW);

                        //Enable the vertex and texture state
                        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, m_vertexBuffer);
                        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, m_textureBuffer);

                        //Draw the vertices as triangles, based on the Index Buffer information
                        gl.glDrawElements(GL10.GL_TRIANGLES, m_indexBuffer.capacity(), GL10.GL_UNSIGNED_SHORT, m_indexBuffer);

                        //Disable the client state before leaving
                        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
                        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
                    }
                }
                finally
                {
                    m_renderInterface.unlockGL();
                }
            }
        }
    }
}
